using Microsoft.Extensions.Logging;
using System.Data;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Uantek.Device.Communication.Utilities
{
    /// <summary>
    /// 数据表达式计算器接口
    /// </summary>
    public interface IDataExpressionEvaluator
    {
        /// <summary>
        /// 计算表达式
        /// </summary>
        /// <param name="expression">表达式字符串</param>
        /// <param name="value">输入值</param>
        /// <param name="variables">变量字典</param>
        /// <returns>计算结果</returns>
        object? Evaluate(string expression, object value, Dictionary<string, object>? variables = null);

        /// <summary>
        /// 验证表达式是否有效
        /// </summary>
        /// <param name="expression">表达式字符串</param>
        /// <returns>验证结果</returns>
        (bool IsValid, string ErrorMessage) ValidateExpression(string expression);

        /// <summary>
        /// 获取表达式中使用的变量
        /// </summary>
        /// <param name="expression">表达式字符串</param>
        /// <returns>变量列表</returns>
        IEnumerable<string> GetVariables(string expression);
    }

    /// <summary>
    /// 数据表达式计算器实现
    /// </summary>
    public class DataExpressionEvaluator : IDataExpressionEvaluator
    {
        private readonly ILogger<DataExpressionEvaluator> _logger;
        private readonly Dictionary<string, Func<object[], object>> _functions;
        private readonly Regex _variableRegex;
        private readonly Regex _functionRegex;

        public DataExpressionEvaluator(ILogger<DataExpressionEvaluator> logger)
        {
            _logger = logger;
            _functions = InitializeFunctions();
            _variableRegex = new Regex(@"\b[a-zA-Z_][a-zA-Z0-9_]*\b", RegexOptions.Compiled);
            _functionRegex = new Regex(@"(\w+)\s*\(([^)]*)\)", RegexOptions.Compiled);
        }

        public object? Evaluate(string expression, object value, Dictionary<string, object>? variables = null)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(expression))
                {
                    return value;
                }

                // 安全检查
                if (!IsSafeExpression(expression))
                {
                    _logger.LogWarning($"不安全的表达式: {expression}");
                    return value;
                }

                // 准备计算上下文
                var context = PrepareContext(value, variables);
                
                // 预处理表达式
                var processedExpression = PreprocessExpression(expression, context);

                // 处理自定义函数
                processedExpression = ProcessCustomFunctions(processedExpression, context);

                // 使用DataTable.Compute进行计算
                var result = EvaluateWithDataTable(processedExpression);

                _logger.LogDebug($"表达式计算: {expression} = {result}");
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"表达式计算失败: {expression}");
                return value; // 返回原始值
            }
        }

        public (bool IsValid, string ErrorMessage) ValidateExpression(string expression)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(expression))
                {
                    return (true, string.Empty);
                }

                // 安全检查
                if (!IsSafeExpression(expression))
                {
                    return (false, "表达式包含不安全的内容");
                }

                // 语法检查
                var testContext = new Dictionary<string, object> { { "value", 1.0 } };
                var processedExpression = PreprocessExpression(expression, testContext);
                processedExpression = ProcessCustomFunctions(processedExpression, testContext);

                // 尝试计算测试表达式
                EvaluateWithDataTable(processedExpression);

                return (true, string.Empty);
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        public IEnumerable<string> GetVariables(string expression)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(expression))
                {
                    return Enumerable.Empty<string>();
                }

                var matches = _variableRegex.Matches(expression);
                var variables = new HashSet<string>();

                foreach (Match match in matches)
                {
                    var variable = match.Value;
                    
                    // 排除数字、保留字和函数名
                    if (!IsNumeric(variable) && !IsReservedWord(variable) && !_functions.ContainsKey(variable))
                    {
                        variables.Add(variable);
                    }
                }

                return variables;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"获取表达式变量失败: {expression}");
                return Enumerable.Empty<string>();
            }
        }

        private Dictionary<string, Func<object[], object>> InitializeFunctions()
        {
            return new Dictionary<string, Func<object[], object>>(StringComparer.OrdinalIgnoreCase)
            {
                // 数学函数
                ["abs"] = args => Math.Abs(Convert.ToDouble(args[0])),
                ["sqrt"] = args => Math.Sqrt(Convert.ToDouble(args[0])),
                ["pow"] = args => Math.Pow(Convert.ToDouble(args[0]), Convert.ToDouble(args[1])),
                ["sin"] = args => Math.Sin(Convert.ToDouble(args[0])),
                ["cos"] = args => Math.Cos(Convert.ToDouble(args[0])),
                ["tan"] = args => Math.Tan(Convert.ToDouble(args[0])),
                ["log"] = args => Math.Log(Convert.ToDouble(args[0])),
                ["log10"] = args => Math.Log10(Convert.ToDouble(args[0])),
                ["exp"] = args => Math.Exp(Convert.ToDouble(args[0])),
                ["ceil"] = args => Math.Ceiling(Convert.ToDouble(args[0])),
                ["floor"] = args => Math.Floor(Convert.ToDouble(args[0])),
                ["round"] = args => args.Length > 1 
                    ? Math.Round(Convert.ToDouble(args[0]), Convert.ToInt32(args[1]))
                    : Math.Round(Convert.ToDouble(args[0])),

                // 条件函数
                ["if"] = args => Convert.ToBoolean(args[0]) ? args[1] : args[2],
                ["max"] = args => args.Max(Convert.ToDouble),
                ["min"] = args => args.Min(Convert.ToDouble),

                // 字符串函数
                ["len"] = args => args[0]?.ToString()?.Length ?? 0,
                ["upper"] = args => args[0]?.ToString()?.ToUpper() ?? string.Empty,
                ["lower"] = args => args[0]?.ToString()?.ToLower() ?? string.Empty,
                ["trim"] = args => args[0]?.ToString()?.Trim() ?? string.Empty,

                // 数据转换函数
                ["toInt"] = args => Convert.ToInt32(args[0]),
                ["toDouble"] = args => Convert.ToDouble(args[0]),
                ["toString"] = args => args[0]?.ToString() ?? string.Empty,
                ["toBool"] = args => Convert.ToBoolean(args[0]),

                // 特殊函数
                ["isnull"] = args => args[0] == null || args[0] == DBNull.Value,
                ["nvl"] = args => args[0] == null || args[0] == DBNull.Value ? args[1] : args[0],
                ["scale"] = args => Convert.ToDouble(args[0]) * Convert.ToDouble(args[1]) + (args.Length > 2 ? Convert.ToDouble(args[2]) : 0),
                ["clamp"] = args => Math.Max(Convert.ToDouble(args[1]), Math.Min(Convert.ToDouble(args[2]), Convert.ToDouble(args[0])))
            };
        }

        private Dictionary<string, object> PrepareContext(object value, Dictionary<string, object>? variables)
        {
            var context = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
            {
                ["value"] = value,
                ["val"] = value,
                ["v"] = value
            };

            if (variables != null)
            {
                foreach (var kvp in variables)
                {
                    context[kvp.Key] = kvp.Value;
                }
            }

            // 添加常用常量
            context["PI"] = Math.PI;
            context["E"] = Math.E;

            return context;
        }

        private string PreprocessExpression(string expression, Dictionary<string, object> context)
        {
            var result = expression;

            // 替换变量
            foreach (var kvp in context)
            {
                var pattern = $@"\b{Regex.Escape(kvp.Key)}\b";
                var replacement = ConvertToString(kvp.Value);
                result = Regex.Replace(result, pattern, replacement, RegexOptions.IgnoreCase);
            }

            // 处理特殊操作符
            result = result.Replace("&&", " AND ");
            result = result.Replace("||", " OR ");
            result = result.Replace("!", " NOT ");

            return result;
        }

        private string ProcessCustomFunctions(string expression, Dictionary<string, object> context)
        {
            var result = expression;
            var matches = _functionRegex.Matches(expression);

            // 从后往前处理，避免位置偏移问题
            for (int i = matches.Count - 1; i >= 0; i--)
            {
                var match = matches[i];
                var functionName = match.Groups[1].Value;
                var argsString = match.Groups[2].Value;

                if (_functions.TryGetValue(functionName, out var function))
                {
                    try
                    {
                        var args = ParseArguments(argsString, context);
                        var functionResult = function(args);
                        var replacement = ConvertToString(functionResult);
                        
                        result = result.Substring(0, match.Index) + replacement + result.Substring(match.Index + match.Length);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"执行函数 {functionName} 失败");
                        // 保留原始函数调用
                    }
                }
            }

            return result;
        }

        private object[] ParseArguments(string argsString, Dictionary<string, object> context)
        {
            if (string.IsNullOrWhiteSpace(argsString))
            {
                return new object[0];
            }

            var args = new List<object>();
            var parts = SplitArguments(argsString);

            foreach (var part in parts)
            {
                var trimmedPart = part.Trim();
                
                if (string.IsNullOrEmpty(trimmedPart))
                {
                    continue;
                }

                // 处理字符串字面量
                if (trimmedPart.StartsWith("\"") && trimmedPart.EndsWith("\""))
                {
                    args.Add(trimmedPart.Substring(1, trimmedPart.Length - 2));
                }
                else if (trimmedPart.StartsWith("'") && trimmedPart.EndsWith("'"))
                {
                    args.Add(trimmedPart.Substring(1, trimmedPart.Length - 2));
                }
                // 处理数值
                else if (double.TryParse(trimmedPart, NumberStyles.Float, CultureInfo.InvariantCulture, out var number))
                {
                    args.Add(number);
                }
                // 处理布尔值
                else if (bool.TryParse(trimmedPart, out var boolean))
                {
                    args.Add(boolean);
                }
                // 处理变量
                else if (context.TryGetValue(trimmedPart, out var variableValue))
                {
                    args.Add(variableValue);
                }
                // 处理表达式
                else
                {
                    try
                    {
                        var processedArg = PreprocessExpression(trimmedPart, context);
                        var argResult = EvaluateWithDataTable(processedArg);
                        args.Add(argResult);
                    }
                    catch
                    {
                        args.Add(trimmedPart);
                    }
                }
            }

            return args.ToArray();
        }

        private List<string> SplitArguments(string argsString)
        {
            var args = new List<string>();
            var current = new System.Text.StringBuilder();
            var inQuotes = false;
            var quoteChar = '\0';
            var parenLevel = 0;

            for (int i = 0; i < argsString.Length; i++)
            {
                var c = argsString[i];

                if (!inQuotes && (c == '"' || c == '\''))
                {
                    inQuotes = true;
                    quoteChar = c;
                    current.Append(c);
                }
                else if (inQuotes && c == quoteChar)
                {
                    inQuotes = false;
                    current.Append(c);
                }
                else if (!inQuotes && c == '(')
                {
                    parenLevel++;
                    current.Append(c);
                }
                else if (!inQuotes && c == ')')
                {
                    parenLevel--;
                    current.Append(c);
                }
                else if (!inQuotes && c == ',' && parenLevel == 0)
                {
                    args.Add(current.ToString());
                    current.Clear();
                }
                else
                {
                    current.Append(c);
                }
            }

            if (current.Length > 0)
            {
                args.Add(current.ToString());
            }

            return args;
        }

        private object EvaluateWithDataTable(string expression)
        {
            try
            {
                var table = new DataTable();
                var result = table.Compute(expression, null);
                return result == DBNull.Value ? null : result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"DataTable计算失败: {expression}");
                throw;
            }
        }

        private bool IsSafeExpression(string expression)
        {
            // 检查危险的关键字和模式
            var dangerousPatterns = new[]
            {
                "System",
                "Assembly",
                "Type",
                "File",
                "Directory",
                "Process",
                "Registry",
                "Environment",
                "AppDomain",
                "Thread",
                "Task",
                "Reflection",
                "Runtime",
                "IO",
                "Net",
                "Security",
                "Cryptography",
                "CodeDom",
                "Compiler",
                "Script",
                "Eval",
                "Execute",
                "Invoke",
                "GetType",
                "typeof",
                "new ",
                "delete ",
                "using ",
                "import ",
                "namespace ",
                "class ",
                "struct ",
                "interface ",
                "enum ",
                "delegate "
            };

            return !dangerousPatterns.Any(pattern => 
                expression.Contains(pattern, StringComparison.OrdinalIgnoreCase));
        }

        private bool IsNumeric(string value)
        {
            return double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out _);
        }

        private bool IsReservedWord(string word)
        {
            var reservedWords = new[]
            {
                "AND", "OR", "NOT", "NULL", "TRUE", "FALSE", "IN", "LIKE", "IS"
            };

            return reservedWords.Contains(word.ToUpper());
        }

        private string ConvertToString(object value)
        {
            if (value == null || value == DBNull.Value)
            {
                return "NULL";
            }

            if (value is string str)
            {
                return $"'{str.Replace("'", "''")}'";
            }

            if (value is bool boolean)
            {
                return boolean ? "1" : "0";
            }

            if (value is DateTime dateTime)
            {
                return $"'{dateTime:yyyy-MM-dd HH:mm:ss}'";
            }

            return Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty;
        }
    }
}